package com.xishu.service;

import com.xishu.bo.ReportBo;
import com.xishu.bo.response.Report;
import com.xishu.bo.shop.ShopReport;
import com.xishu.config.Constant;
import com.xishu.dao.jpa.*;
import com.xishu.entity.AbstractEntity;
import com.xishu.entity.customer.VipLevel;
import com.xishu.entity.feedback.Feedback;
import com.xishu.entity.order.*;
import com.xishu.entity.shop.*;
import com.xishu.exception.ResponseStatusException;
import com.xishu.response.VerifyUtil;
import com.xishu.service.order.base.OrderService;
import com.xishu.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import javax.persistence.Tuple;
import java.io.File;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.xishu.config.Constant.*;

public class ReportService implements Tools {
    public static final Map<Long, String> PAY_TYPE_MAP = new HashMap<>();
    public static final Map<Long, String> ORDER_TYPE_MAP_ZH = new HashMap<>();
    public static final Map<Long, String> ORDER_TYPE_MAP_EN = new HashMap<>();
    private static ReportService instance = new ReportService();
    private CommonService commonService = CommonService.getInstance();
    private static Logger logger = LoggerFactory.getLogger(ReportService.class);

    private ReportService() {
        PAY_TYPE_MAP.put(Constant.PAY_TYPE_WEIXIN, "微信支付");
        PAY_TYPE_MAP.put(Constant.PAY_TYPE_ALI_PAY, "支付宝支付");
        PAY_TYPE_MAP.put(Constant.PAY_TYPE_CASH, "现金");

        ORDER_TYPE_MAP_ZH.put(Constant.ORDER_REPORT_TYPE_TANG_SHI, "堂食");
        ORDER_TYPE_MAP_ZH.put(Constant.ORDER_REPORT_TYPE_TAKE_OUT, "外賣");
        ORDER_TYPE_MAP_ZH.put(Constant.ORDER_REPORT_TYPE_TAKE_OUT_PLAT, "外賣平台");

        ORDER_TYPE_MAP_EN.put(Constant.ORDER_REPORT_TYPE_TANG_SHI, "Here");
        ORDER_TYPE_MAP_EN.put(Constant.ORDER_REPORT_TYPE_TAKE_OUT, "Take Out");
        ORDER_TYPE_MAP_EN.put(Constant.ORDER_REPORT_TYPE_TAKE_OUT_PLAT, "Delivery Platform");
    }

    public static ReportService getInstance() {
        return instance;
    }

    /**
     * 获取支付类型
     *
     * @param payType
     * @return
     */
    public String getPayTypeString(Long payType) {
        return PAY_TYPE_MAP.getOrDefault(payType, "");
    }

    /**
     * 通过开始时间以及结束时间来计算出时间单位，是小时，是天，还是月
     *
     * @param startTime
     * @param endTime
     * @return
     */
    public Long calTimeUnit(Long startTime, Long endTime) {
        //两天以内采用小时
        //超过2天，小于2个月采用天
        //超过2个月，小于6个月采用半个月
        //超过6个月，采用月
        if (endTime - startTime > DateUtil.ONE_MONTH * 6) {
            return DateUtil.ONE_MONTH;
        } else if (endTime - startTime > DateUtil.ONE_MONTH * 2) {
            return DateUtil.HALF_MONTH;
        } else if (endTime - startTime > DateUtil.ONE_DAY * 2) {
            return DateUtil.ONE_DAY;
        } else {
            return DateUtil.ONE_HOUR;
        }
    }

    /**
     * 获取时间格式
     *
     * @param reportBo
     * @return
     */
    public Long getTimeUnit(ReportBo reportBo) {
        Long timeUnit = reportBo.getTimeUnit();

        if (timeUnit == null) {
            timeUnit = calTimeUnit(reportBo.getStartTime(), reportBo.getEndTime());
        }

        return timeUnit;
    }

    /**
     * 获取时间的格式
     *
     * @param timeUnit
     * @return
     */
    public String getTimeFormat(Long timeUnit) {
        if (timeUnit == DateUtil.ONE_MONTH) {
            return "%Y-%m";
        } else if (timeUnit == DateUtil.ONE_DAY) {
            return "%Y-%m-%d";
        } else {
            return "%Y-%m-%d %H";
        }
    }

    /**
     * 品类的报表
     *
     * @param reportBo
     * @return
     */
    public List<Report> catalogReport(ReportBo reportBo) throws Exception {
        ReportBo reportBoClone = (ReportBo) ClassUtil.clone(reportBo);
        OrderCatalogMappingDao orderCatalogMappingDao = BeanUtil.getBean(OrderCatalogMappingDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);

        //报表集合
        List<Report> reportList = null;


        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {
            List<Report> totalAmountOrQtyList;
            if (equals(reportBo.getAmountQtyType(), BY_AMOUNT_FIND)) {
                totalAmountOrQtyList = catalogTotalAmount(reportBo);
            } else {
                totalAmountOrQtyList = catalogTotalQty(reportBo);
            }

            List<Catalog> catalogList = new ArrayList<>();
            //重新根据catalogId来写中英文，处理国际化
            for (Report report : totalAmountOrQtyList) {
                Long catalogId = report.getTmpId();
                Optional<Catalog> catalogOptional = CatalogService.getInstance().findCatalog(catalogId, catalogList);
                if (catalogOptional.isPresent()) {
                    Catalog catalog = catalogOptional.get();
                    report.setY_zh(catalog.getName_zh());
                    report.setY_en(catalog.getName_en());
                }
            }
            totalAmountOrQtyList = itemOrCatalogMoneyOrQtySort(totalAmountOrQtyList, reportBoClone);

            //小数处理
            totalAmountOrQtyList.forEach((r) -> {
                Double moneyDouble = showMoneyDouble(r.getValue());
                r.setValue(moneyDouble);
            });

            return totalAmountOrQtyList;
        }




        //年月日
        //带品类id集合的金额查询
        if (equals(reportBo.getAmountQtyType(), BY_AMOUNT_FIND)) {
            List<Tuple> catalogTuples = new ArrayList<>();

            if (isNotEmpty(reportBo.getNameZhTypeList())) {
                //中文
                List<Tuple> catalogTupleList = orderCatalogMappingDao.reportZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getNameZhTypeList());
                catalogTuples.addAll(catalogTupleList);
            }

            if (isNotEmpty(reportBo.getNameEnTypeList())) {
                //英文
                List<Tuple> catalogTupleList = orderCatalogMappingDao.reportEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getNameEnTypeList());
                catalogTuples.addAll(catalogTupleList);
            }
            if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())) {

                //不带名称集合查询
                List<Tuple> catalogTupleList = orderCatalogMappingDao.report(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat);
                catalogTuples.addAll(catalogTupleList);
            }

            reportList = dbResultToReportList(timeUnit, catalogTuples);
        }



        //带品类id集合的数量查询
        if (equals(reportBo.getAmountQtyType(), BY_QTY_FIND)) {
            List<Tuple> catalogTuples = new ArrayList<>();

            if (isNotEmpty(reportBo.getNameZhTypeList())) {
                //中文
                List<Tuple> catalogTupleList = orderCatalogMappingDao.reportQtyZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getNameZhTypeList());
                catalogTuples.addAll(catalogTupleList);
            }

            if (isNotEmpty(reportBo.getNameEnTypeList())){
                //英文
                List<Tuple> catalogTupleList = orderCatalogMappingDao.reportQtyEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getNameEnTypeList());
                catalogTuples.addAll(catalogTupleList);
            }

            if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())){
                //不带名称集合查询
                List<Tuple> catalogTupleList = orderCatalogMappingDao.reportQty(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat);
                catalogTuples.addAll(catalogTupleList);

            }

            reportList = dbResultToReportList(timeUnit, catalogTuples);
        }


        List<Catalog> catalogList = new ArrayList<>();
        //重新根据catalogId来写中英文
        if (isNotEmpty(reportList)) {
            for (Report report : reportList) {
                Long catalogId = report.getTmpId();
                Optional<Catalog> catalogOptional = CatalogService.getInstance().findCatalog(catalogId, catalogList);
                if (catalogOptional.isPresent()) {
                    Catalog catalog = catalogOptional.get();
                    report.setY_zh(catalog.getName_zh());
                    report.setY_en(catalog.getName_en());
                }
            }
        }
        //对年月日选项排序
        reportList = itemOrCatalogMoneyOrQtySort(reportList, reportBoClone);
        //小数处理
        reportList.forEach((r) -> {
            Double moneyDouble = showMoneyDouble(r.getValue());
            r.setValue(moneyDouble);
        });

        return reportList;
    }

    /**
     * 品类数量总计查询
     *
     * @param reportBo
     * @return
     */
    private List<Report> catalogTotalQty(ReportBo reportBo) {
        OrderCatalogMappingDao orderCatalogMappingDao = BeanUtil.getBean(OrderCatalogMappingDao.class);
        List<Tuple> catalogTotalAmountOrQtyList = null;

        if (isNotEmpty(reportBo.getNameZhTypeList())) {
            //中文
            catalogTotalAmountOrQtyList = orderCatalogMappingDao.idTotalQtyZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getNameZhTypeList());

        }

        if (isNotEmpty(reportBo.getNameEnTypeList())) {
            //英文
            catalogTotalAmountOrQtyList = orderCatalogMappingDao.idTotalQtyEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getNameEnTypeList());

        }
        if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())) {

            //不带品类id集合查数量
            catalogTotalAmountOrQtyList = orderCatalogMappingDao.TotalQty(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime());

        }

        List<Report> totalReportList = catalogTotalAmountOrQtyList.stream().map(p -> {
            Report report = new Report();
            NativeResultProcessUtils.convertTupleToBean(p, report);
            return report;
        }).collect(Collectors.toList());


        return totalReportList;
    }


    /**
     * 品类金额总计查询
     *
     * @param reportBo
     * @return
     */
    private List<Report> catalogTotalAmount(ReportBo reportBo) {
        OrderCatalogMappingDao orderCatalogMappingDao = BeanUtil.getBean(OrderCatalogMappingDao.class);
        List<Tuple> catalogTotalAmountOrQtyList = null;

        List<String> nameZhTypeList = reportBo.getNameZhTypeList();

        if (isNotEmpty(nameZhTypeList)) {
            //中文
            catalogTotalAmountOrQtyList = orderCatalogMappingDao.idTotalAmountZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), nameZhTypeList);
        }

        if (isNotEmpty(reportBo.getNameEnTypeList())) {
            //英文
            catalogTotalAmountOrQtyList = orderCatalogMappingDao.idTotalAmountEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), nameZhTypeList);

        }
        if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())) {

            //不带名称集合查询
            catalogTotalAmountOrQtyList = orderCatalogMappingDao.totalAmount(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime());
        }

        List<Report> totalReportList = catalogTotalAmountOrQtyList.stream().map(p -> {
            Report report = new Report();
            NativeResultProcessUtils.convertTupleToBean(p, report);
            return report;
        }).collect(Collectors.toList());


        return totalReportList;
    }


    /**
     * 分类映射数量
     *
     * @param reportBo
     * @return
     */
    public List<Report> catalogCount(ReportBo reportBo) {
        OrderCatalogMappingDao orderCatalogMappingDao = BeanUtil.getBean(OrderCatalogMappingDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        List<Tuple> list = orderCatalogMappingDao.count(reportBo.getShopId(), reportBo.getStartTime(), reportBo.getEndTime());
        List<Report> reportList = dbResultToReportList(timeUnit, list);
        return reportList;
    }

    /**
     * 将数据库查询的结果转化成报表
     *
     * @param timeUnit
     * @param list
     * @return
     */
    public List<Report> dbResultToReportList(Long timeUnit, List<Tuple> list) {
        List<Report> reportList = list.stream().map(p -> {
            Report report = new Report();
            NativeResultProcessUtils.convertTupleToBean(p, report);

            if (report.getxTime() != null) {
                long time = (long) (report.getxTime() * timeUnit);

                //再返回成时间戳
                if (timeUnit == DateUtil.ONE_HOUR) {
                    report.setX(DateUtil.format(time, "yyyy-MM-dd HH"));
                } else if (timeUnit == DateUtil.ONE_DAY) {
                    report.setX(DateUtil.format(time, "MM-dd"));
                } else if (timeUnit == DateUtil.HALF_MONTH) {
                    report.setX(DateUtil.format(time, "MM-dd"));
                } else if (timeUnit == DateUtil.ONE_MONTH) {
                    report.setX(DateUtil.format(time, "yyyy-MM"));
                }
            }

            report.setValue(formatDouble(report.getValue()));
            return report;
        }).collect(Collectors.toList());
        return reportList;
    }

    /**
     * 菜品的报表,只取 TOP3
     *
     * @param reportBo
     * @return
     */
    public List<Report> itemReport(ReportBo reportBo) throws Exception {
        OrderItemMappingDao orderItemMappingDao = BeanUtil.getBean(OrderItemMappingDao.class);
        ReportBo reportBoClone = (ReportBo) ClassUtil.clone(reportBo);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        List<Report> totalAmountOrQtyList = null;
        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {
            if (equals(reportBo.getAmountQtyType(), BY_AMOUNT_FIND)) {
                totalAmountOrQtyList = itemTotalAmount(reportBo);
            } else {
                //按照数量排序,
                totalAmountOrQtyList = itemTotalQty(reportBo);
            }
            //国际化
            for (Report report : getList(totalAmountOrQtyList)) {
                Long catalogId = report.getTmpId();
                if (isNotEmpty(catalogId) && report.getTmpId() > 0) {

                    Item itemInDb = null;
                    try {
                        itemInDb = ItemService.getInstance().findItem(catalogId);
                    } catch (Exception e) {
                    }
                    if (itemInDb != null) {
                        if (isNotEmpty(itemInDb.getName())) {
                            report.setY(itemInDb.getName());
                        }
                        if (isNotEmpty(itemInDb.getName_zh())) {
                            report.setY_zh(itemInDb.getName_zh());
                        }
                        if (isNotEmpty(itemInDb.getName_en())) {
                            report.setY_en(itemInDb.getName_en());
                        }
                    }
                }
            }
            totalAmountOrQtyList = itemOrCatalogMoneyOrQtySort(totalAmountOrQtyList, reportBoClone);


            //小数处理
            totalAmountOrQtyList.forEach((r) -> {
                Double moneyDouble = showMoneyDouble(r.getValue());
                r.setValue(moneyDouble);
            });

            return totalAmountOrQtyList;
        }


        //年月日 金额
        if (equals(reportBo.getAmountQtyType(), BY_AMOUNT_FIND)) {
            if (isNotEmpty(reportBo.getNameZhTypeList())) {
                //中文
                List<Tuple> itemTupleList = orderItemMappingDao.listIdToReportAmountZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getNameZhTypeList());
                totalAmountOrQtyList = dbResultToReportList(timeUnit, itemTupleList);
            }

            if (isNotEmpty(reportBo.getNameEnTypeList())){
                //英文
                List<Tuple> itemTupleList = orderItemMappingDao.listIdToReportAmountEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getNameEnTypeList());
                totalAmountOrQtyList = dbResultToReportList(timeUnit, itemTupleList);
            }
            if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())){
                //不带名称集合查询
                List<Tuple> itemTupleList = orderItemMappingDao.reportAmount(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat);
                totalAmountOrQtyList = dbResultToReportList(timeUnit, itemTupleList);
            }
        }else {


            if (isNotEmpty(reportBo.getNameZhTypeList())) {
                //中文
                List<Tuple> itemTupleList = orderItemMappingDao.listIdToReportQtyZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getNameZhTypeList());
                totalAmountOrQtyList = dbResultToReportList(timeUnit, itemTupleList);
            }

            if (isNotEmpty(reportBo.getNameEnTypeList())){
                //英文
                List<Tuple> itemTupleList = orderItemMappingDao.listIdToReportQtyEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getNameEnTypeList());
                totalAmountOrQtyList = dbResultToReportList(timeUnit, itemTupleList);
            }
            if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())){

                //不带名称集合查询
                List<Tuple> itemTupleList = orderItemMappingDao.reportQty(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat);
                totalAmountOrQtyList = dbResultToReportList(timeUnit, itemTupleList);
            }

        }

        //处理国际化
        for (Report report : getList(totalAmountOrQtyList)) {
            Long catalogId = report.getTmpId();
            if (isNotEmpty(catalogId) && report.getTmpId() > 0) {

                Item itemInDb = null;
                try {
                    itemInDb = ItemService.getInstance().findItem(catalogId);
                } catch (Exception e) {
                }
                if (itemInDb != null) {
                    if (isNotEmpty(itemInDb.getName())) {
                        report.setY(itemInDb.getName());
                    }
                    if (isNotEmpty(itemInDb.getName_zh())) {
                        report.setY_zh(itemInDb.getName_zh());
                    }
                    if (isNotEmpty(itemInDb.getName_en())) {
                        report.setY_en(itemInDb.getName_en());
                    }
                }
            }
        }

        //给年月日选项排序
        totalAmountOrQtyList = itemOrCatalogMoneyOrQtySort(getList(totalAmountOrQtyList), reportBoClone);

        List<Item> itemList = new ArrayList<>();
        for (Report report : totalAmountOrQtyList) {
            //特别菜单独处理
            if (equals(report.getTmpId(), SPECIAL_ITEM)) {
                report.setY_zh(SPECIAL_ITEM_NAME_ZH);
                report.setY_en(SPECIAL_ITEM_NAME_EN);
            } else {
                Optional<Item> itemOption = ItemService.getInstance().findItemOption(report.getTmpId(), itemList);
                if (itemOption.isPresent()) {
                    Item item = itemOption.get();
                    report.setY_zh(item.getName_zh());
                    report.setY_en(item.getName_en());
                }
            }
        }

        //小数处理
        totalAmountOrQtyList.forEach((r) -> {
            Double moneyDouble = showMoneyDouble(r.getValue());
            r.setValue(moneyDouble);
        });

        return totalAmountOrQtyList;
    }

    private List<Report> itemTotalQty(ReportBo reportBo) {
        OrderItemMappingDao orderItemMappingDao = BeanUtil.getBean(OrderItemMappingDao.class);

        List<Tuple> tupleArrayList = null;

        if (isNotEmpty(reportBo.getNameZhTypeList())) {
            //中文
            tupleArrayList = orderItemMappingDao.idTotalQtyZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getNameZhTypeList());
        }

        if (isNotEmpty(reportBo.getNameEnTypeList())){
            //英文
            tupleArrayList = orderItemMappingDao.idTotalQtyEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getNameEnTypeList());
        }
        if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())){

            //不带名称集合查询
            tupleArrayList = orderItemMappingDao.totalQty(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime());
        }
        List<Report> totalReportList = tupleArrayList.stream().map(p -> {
            Report report = new Report();
            NativeResultProcessUtils.convertTupleToBean(p, report);
            return report;
        }).collect(Collectors.toList());


        return totalReportList;
    }


    /**
     * 每个菜品金额总计
     *
     * @param reportBo
     * @return
     */
    private List<Report> itemTotalAmount(ReportBo reportBo) {
        OrderItemMappingDao orderItemMappingDao = BeanUtil.getBean(OrderItemMappingDao.class);

        List<Tuple> tupleArrayList = null;

        if (isNotEmpty(reportBo.getNameZhTypeList())) {
            //中文
            tupleArrayList = orderItemMappingDao.idTotalAmountZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getNameZhTypeList());
        }

        if (isNotEmpty(reportBo.getNameEnTypeList())){
            //英文
            tupleArrayList = orderItemMappingDao.idTotalAmountEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getNameEnTypeList());
        }
        if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())){

            //不带名称集合查询
            tupleArrayList = orderItemMappingDao.totalAmount(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime());
        }

        List<Report> totalReportList = tupleArrayList.stream().map(p -> {
            Report report = new Report();
            NativeResultProcessUtils.convertTupleToBean(p, report);
            return report;
        }).collect(Collectors.toList());


        return totalReportList;
    }

    /**
     * 金额或数量排序
     *
     * @param sortList
     * @return
     */
    public List<Report> itemOrCatalogMoneyOrQtySort(List<Report> sortList, ReportBo reportBo) {
        //排序结果集
        List<Report> reportTopList = new ArrayList<>();
        if (isEmpty(sortList)) {
            return reportTopList;
        }
        //分组求和
        Map<String, Double> reportGroupingSumMap = sortList.stream().filter((s) -> s.getTmpId() != null && s.getValue() != null && s.getValue() != 0.0).collect(Collectors.groupingBy((m) -> m.getTmpId().toString(), Collectors.summingDouble(Report::getValue)));
        //按照名字，独立解决优惠券
        if (isEmpty(reportGroupingSumMap)) {
            reportGroupingSumMap = sortList.stream().filter((s) -> s.getY() != null && s.getValue() != null && s.getValue() != 0.0).collect(Collectors.groupingBy((m) -> m.getY(), Collectors.summingDouble(Report::getValue)));
        }
        //按照数量，独立解决退款理由
        if (isEmpty(reportGroupingSumMap)) {
            reportGroupingSumMap = sortList.stream().filter((s) -> s.getTmpId() != null && s.getCount() != null).collect(Collectors.groupingBy((m) -> m.getTmpId().toString(), Collectors.summingDouble(Report::getCount)));
        }
        //如果还没有数据，就不用排序了
        if (isEmpty(reportGroupingSumMap)) {
            return reportTopList;
        }
        //找出排名，因为reversed出问题，就用升序处理
        LinkedHashMap<String, Double> reportMap = reportGroupingSumMap.entrySet()
                .stream().sorted(Map.Entry.comparingByValue())
                .collect(Collectors.toMap(
                        Map.Entry::getKey,
                        Map.Entry::getValue,
                        (oldVal, newVal) -> oldVal,
                        LinkedHashMap::new));
        //数值越大的越在后边
        List<String> reportKeysList = new ArrayList<>(reportMap.keySet());

        //IdTypeList是空才top3
        if (isEmpty(reportBo.getNameZhTypeList())&&isEmpty(reportBo.getNameEnTypeList()) && reportKeysList.size() > 3) {
            reportKeysList = reportKeysList.subList(reportKeysList.size() - 3, reportKeysList.size());
        }

        //给结果集排序，
        for (int i = reportKeysList.size() - 1; i >= 0; i--) {
            for (Report report : sortList) {
                String s = reportKeysList.get(i);
                if (isNotEmpty(report.getTmpId()) && s.equals(report.getTmpId().toString())) {
                    reportTopList.add(report);
                } else if (!isNotEmpty(report.getTmpId()) && s.equals(report.getY())) {
                    reportTopList.add(report);
                } else if (isNotEmpty(report.getX()) && s.equals(report.getX())) {
                    reportTopList.add(report);
                }
            }
        }
        //top3加上其他
        if (!isNotEmpty(reportBo.getTimeUnit()) && isEmpty(reportBo.getNameZhTypeList())&&isEmpty(reportBo.getNameEnTypeList())) {
            //总共价格
            Double count = 0.0;
            for (Report report : sortList) {
                if (!equals(report.getValue(), 0.0) && report.getValue() != null) {
                    count = count + report.getValue();
                } else if (report.getCount() != null) {
                    count = count + report.getCount();
                }

            }
            Double top3 = 0.0;
            //top3的价格
            for (Report report : reportTopList) {
                if (!equals(report.getValue(), 0.0) && report.getValue() != null) {
                    top3 = top3 + report.getValue();
                } else if (report.getCount() != null) {
                    top3 = top3 + report.getCount();
                }
            }
            double other = count - top3;
            Report report = new Report();
            report.setValue(other);
            report.setY("其他");
            report.setY_zh("其他");
            report.setY_en("other");

            if (!equals(other, 0.0)) {
                reportTopList.add(report);
            }

        }

        //国际化处理
        for (Report report : reportTopList) {
            if (isNotEmpty(report.getY())) {
                if (isEmpty(report.getY_zh())) {
                    report.setY_zh(report.getY());
                }
                if (isEmpty(report.getY_en())) {
                    report.setY_en(report.getY());
                }
            }
        }
        return reportTopList;
    }

    /**
     * 支付方式的报表
     *
     * @param reportBo
     * @return
     */
    public List<Report> payTypeReport(ReportBo reportBo) {
        OrderPayTypeMappingDao orderPayTypeMappingDao = BeanUtil.getBean(OrderPayTypeMappingDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        List<Tuple> list = null;
        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {

            if (isNotEmpty(reportBo.getNameZhTypeList())) {
                //中文
                list = orderPayTypeMappingDao.ListIdReportTotalZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getNameZhTypeList());

            }

            if (isNotEmpty(reportBo.getNameEnTypeList())){
                //英文
                list = orderPayTypeMappingDao.ListIdReportTotalEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getNameEnTypeList());

            }
            if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())){
                //不带名称集合查询
                list = orderPayTypeMappingDao.reportTotal(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime());

            }

            List<Report> reportList = dbResultToReportList(timeUnit, list);

            List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
            //小数处理
            reports.forEach((r) -> {
                Double moneyDouble = showMoneyDouble(r.getValue());
                r.setValue(moneyDouble);
            });
            return reports;
        }

        //年月日

        if (isNotEmpty(reportBo.getNameZhTypeList())) {
            //中文
            list = orderPayTypeMappingDao.ListIdReportZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getNameZhTypeList());

        }

        if (isNotEmpty(reportBo.getNameEnTypeList())){
            //英文
            list = orderPayTypeMappingDao.ListIdReportEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getNameEnTypeList());

        }

        if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())){
            //不带名称集合查询
            list = orderPayTypeMappingDao.report(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat);

        }


        List<Report> reportList = dbResultToReportList(timeUnit, list);
        List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
        //小数处理
        reports.forEach((r) -> {
            Double moneyDouble = showMoneyDouble(r.getValue());
            r.setValue(moneyDouble);
        });
        return reports;
    }

    /**
     * 支付方式当天的报表
     *
     * @param reportBo
     * @return
     */
    public List<Report> payTypeCount(ReportBo reportBo) {
        OrderPayTypeMappingDao orderPayTypeMappingDao = BeanUtil.getBean(OrderPayTypeMappingDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        List<Tuple> list = orderPayTypeMappingDao.count(reportBo.getShopId(), reportBo.getStartTime(), reportBo.getEndTime());
        List<Report> reportList = dbResultToReportList(timeUnit, list);
        return reportList;
    }

    /**
     * 点餐种类的报表
     *
     * @param reportBo
     * @return
     */
    public List<Report> orderTypeReport(ReportBo reportBo) {
        OrderTypeMappingDao orderTypeMappingDao = BeanUtil.getBean(OrderTypeMappingDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        List<Tuple> list = null;
        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {
            list = orderTypeMappingDao.reportTotal(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime());
            List<Report> reportList = dbResultToReportList(timeUnit, list);
            List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
            //再将tmpId转化成字符串显示
            reports.forEach(p -> {
                String payType = ORDER_TYPE_MAP_ZH.get(p.getTmpId());
                p.setY(payType);
                p.setY_zh(ORDER_TYPE_MAP_ZH.get(p.getTmpId()));
                p.setY_en(ORDER_TYPE_MAP_EN.get(p.getTmpId()));
            });
            //小数处理
            reports.forEach((r) -> {
                Double moneyDouble = showMoneyDouble(r.getValue());
                r.setValue(moneyDouble);
            });
            return reports;
        }
        //年月日
        list = orderTypeMappingDao.report(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat);
        List<Report> reportList = dbResultToReportList(timeUnit, list);
        List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
        //再将tmpId转化成字符串显示
        reports.forEach(p -> {
            String payType = ORDER_TYPE_MAP_ZH.get(p.getTmpId());
            p.setY(payType);
            p.setY_zh(ORDER_TYPE_MAP_ZH.get(p.getTmpId()));
            p.setY_en(ORDER_TYPE_MAP_EN.get(p.getTmpId()));
        });
        //小数处理
        reports.forEach((r) -> {
            Double moneyDouble = showMoneyDouble(r.getValue());
            r.setValue(moneyDouble);
        });
        return reports;
    }

    /**
     * 打印机上面的显示的金额，按照支付类型以及订单类型分组
     *
     * @param reportBo
     * @return
     */
    public List<Report> orderTypeForPrinter(ReportBo reportBo) {
        OrderPayTypeMappingDao orderPayTypeMappingDao = BeanUtil.getBean(OrderPayTypeMappingDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        List<Tuple> list = orderPayTypeMappingDao.group(reportBo.getShopId(), reportBo.getStartTime(), reportBo.getEndTime());
        List<Report> reportList = dbResultToReportList(timeUnit, list);
        return reportList;
    }

    /**
     * 订单类型计数
     *
     * @param reportBo
     * @return
     */
    public List<Report> orderTypeCount(ReportBo reportBo) {
        OrderTypeMappingDao orderTypeMappingDao = BeanUtil.getBean(OrderTypeMappingDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        List<Tuple> list = orderTypeMappingDao.count(reportBo.getShopId(), reportBo.getStartTime(), reportBo.getEndTime());
        List<Report> reportList = dbResultToReportList(timeUnit, list);
        return reportList;
    }

    /**
     * 服务员的报表
     *
     * @param reportBo
     * @return
     */
    public List<Report> waiterReport(ReportBo reportBo) {
        OrderWaiterMappingDao orderWaiterMappingDao = BeanUtil.getBean(OrderWaiterMappingDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        List<Tuple> list = null;
        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {

            if (isNotEmpty(reportBo.getNameZhTypeList())) {
                //中文
                list = orderWaiterMappingDao.idReportTotalZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(),reportBo.getNameZhTypeList());
            }

            if (isNotEmpty(reportBo.getNameEnTypeList())){
                //英文
                list = orderWaiterMappingDao.idReportTotalEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(),reportBo.getNameZhTypeList());

            }
            if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())){

                //不带名称集合查询
                list = orderWaiterMappingDao.reportTotal(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime());
            }
            List<Report> reportList = dbResultToReportList(timeUnit, list);
            List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
            //小数处理
            reports.forEach((r) -> {
                Double moneyDouble = showMoneyDouble(r.getValue());
                r.setValue(moneyDouble);
            });
            return reports;
        }
        //年月日
        if (isNotEmpty(reportBo.getNameZhTypeList())) {
            //中文
            list = orderWaiterMappingDao.idReportZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat,reportBo.getNameZhTypeList());
        }

        if (isNotEmpty(reportBo.getNameEnTypeList())){
            //英文
            list = orderWaiterMappingDao.idReportEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat,reportBo.getNameEnTypeList());

        }
        if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())){

            //不带名称集合查询
            list = orderWaiterMappingDao.report(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat);
        }

        List<Report> reportList = dbResultToReportList(timeUnit, list);
        List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
        //小数处理
        reports.forEach((r) -> {
            Double moneyDouble = showMoneyDouble(r.getValue());
            r.setValue(moneyDouble);
        });
        return reports;
    }

    /**
     * 优惠卷的报表
     *
     * @param reportBo
     * @return
     */
    public List<Report> discountTicketReport(ReportBo reportBo) {
        OrderDiscountTicketMappingDao orderDiscountTicketMappingDao = BeanUtil.getBean(OrderDiscountTicketMappingDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        //得到优惠券名称
        DiscountTicketDao discountTicketDao = BeanUtil.getBean(DiscountTicketDao.class);
        List<Tuple> reports = null;
        if (isNotEmpty(reportBo.getIdTypeList())) {
            reports = discountTicketDao.idTicketReport(reportBo.getIdTypeList());
        } else {
            reports = discountTicketDao.TicketReport(reportBo.getCompanyId());
        }

        List<Report> reportsNameList = reports.stream().map(p -> {
            Report report = new Report();
            NativeResultProcessUtils.convertTupleToBean(p, report);
            return report;
        }).collect(Collectors.toList());

        List<String> discountNameList = new ArrayList<>();
        for (Report report : reportsNameList) {
            discountNameList.add(report.getY());
        }
        List<Tuple> list = null;
        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {
            if (isNotEmpty(reportBo.getIdTypeList())) {
                list = orderDiscountTicketMappingDao.idReportTotal(reportBo.getStartTime(), reportBo.getEndTime(), discountNameList);
            } else {
                list = orderDiscountTicketMappingDao.reportTotal(reportBo.getStartTime(), reportBo.getEndTime());
            }


            List<Report> reportList = dbResultToReportList(timeUnit, list);
            List<Report> reportsList = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
            //小数处理
            reportsList.forEach((r) -> {
                Double moneyDouble = showMoneyDouble(r.getValue());
                r.setValue(moneyDouble);
            });
            return reportsList;
        }
        //年月日
        if (isNotEmpty(reportBo.getIdTypeList())) {
            list = orderDiscountTicketMappingDao.idReport(reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, discountNameList);
        } else {
            list = orderDiscountTicketMappingDao.report(reportBo.getStartTime(), reportBo.getEndTime(), timeFormat);

        }

        List<Report> reportList = dbResultToReportList(timeUnit, list);
        List<Report> reportsList = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
        ArrayList<Report> reportArrayList = new ArrayList<>();
        reportsList.forEach(report -> {
            reportArrayList.add(report);
        });
        reportArrayList.forEach((r) -> {
            Double moneyDouble = showMoneyDouble(r.getValue());
            r.setValue(moneyDouble);
        });
        return reportArrayList;
    }

    /**
     * 顾客反馈的报表
     *
     * @param reportBo
     * @return
     */
    public List<Report> feedbackReport(ReportBo reportBo) {
        FeedbackDao feedbackDao = BeanUtil.getBean(FeedbackDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        List<Tuple> list = feedbackDao.report(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat);
        List<Report> reportList = dbResultToReportList(timeUnit, list);

        reportList.forEach(report -> {
            report.setY("star");
        });

        return reportList;
    }

    /**
     * 退款理由
     *
     * @param reportBo
     * @return
     */
    public List<Report> reasonReport(ReportBo reportBo) {
        ReasonDao reasonDao = BeanUtil.getBean(ReasonDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        List<Tuple> list;
        //国际化
        Map<Long, String> mapZh = new HashMap<>();
        mapZh.put(REASON_TYPE_CUSTOMER_RETURN, "客人退菜");
        mapZh.put(REASON_TYPE_CUSTOMER, "庫存不足");
        mapZh.put(REASON_TYPE_WRONG_OPERATOR, "服務員錯誤操作");
        mapZh.put(REASON_TYPE_OTHER, "其它");
        mapZh.put(REASON_TYPE_TOTAL, "總計");

        Map<Long, String> mapEn = new HashMap<>();
        mapEn.put(REASON_TYPE_CUSTOMER_RETURN, "Customer Return");
        mapEn.put(REASON_TYPE_CUSTOMER, "Run Out Stock");
        mapEn.put(REASON_TYPE_WRONG_OPERATOR, "Server Mistakes");
        mapEn.put(REASON_TYPE_OTHER, "Other");
        mapEn.put(REASON_TYPE_TOTAL, "Total");

        //退款选项各个分店是固定，就按原来的只添加多分店
        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {
            if (isNotEmpty(reportBo.getIdTypeList())) {
                list = reasonDao.idReportTotal(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getIdTypeList());
            } else {
                list = reasonDao.reportTotal(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime());
            }
            List<Report> reportList = dbResultToReportList(timeUnit, list);
            if (isEmpty(reportBo.getIdTypeList())){
                ArrayList<String> strings = new ArrayList<>();
                strings.add("特殊处理，如果IdTypeList是null，排序防止top3");
                reportBo.setNameEnTypeList(strings);
            }
            List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
            //国际化
            for (Report report : reports) {
                if (isNotEmpty(report.getTmpId())) {
                    report.setY(report.getTmpId() + "");
                    if (isNotEmpty(report.getCount())) {
                        report.setValue(Double.valueOf(report.getCount() + ""));
                    }
                    report.setY_zh(mapZh.get(report.getTmpId()));
                    report.setY_en(mapEn.get(report.getTmpId()));
                }
            }
            return reports;
        }
        //年月日
        if (isNotEmpty(reportBo.getIdTypeList())) {
            list = reasonDao.idReport(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getIdTypeList());
        } else {
            list = reasonDao.report(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat);
        }

        List<Report> reportList = dbResultToReportList(timeUnit, list);
        List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
        //国际化
        for (Report report : reports) {
            if (isNotEmpty(report.getTmpId())) {
                report.setY(report.getTmpId() + "");
                if (isNotEmpty(report.getCount())) {
                    report.setValue(Double.valueOf(report.getCount() + ""));
                }
                report.setY_zh(mapZh.get(report.getTmpId()));
                report.setY_en(mapEn.get(report.getTmpId()));
            }
        }

        return reports;
    }

    /**
     * 分店总报告,显示每个分店的信息
     *
     * @param reportBo
     * @return
     */
    public List<Report> shopReport(ReportBo reportBo) {
        //随便设置的值，目的不用top3
        ArrayList<Long> IdType = new ArrayList<>();
        IdType.add(1L);
        reportBo.setIdTypeList(IdType);

        OrderDao reasonDao = BeanUtil.getBean(OrderDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        List<Tuple> list;
        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {
            list = reasonDao.shopReportTotal(reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getShopIdList());
            List<Report> reportList = dbResultToReportList(timeUnit, list);
            List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
            //写数据
            reports.forEach(data -> {
                try {
                    Long shopId = data.getTmpId();
                    Shop shop = ShopService.getInstance().findShopById(shopId);
                    data.setY_zh(shop.getName_zh());
                    data.setY_en(shop.getName_en());
                } catch (Exception e) {
                    logger.error("e", e);
                }
            });

            //小数处理
            reports.forEach((r) -> {
                Double moneyDouble = showMoneyDouble(r.getValue());
                r.setValue(moneyDouble);
            });
            return reports;
        }
        //年月日
        if (reportBo.getShopId() != null) {
            //不带id
            list = reasonDao.shopReport(reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getShopId());
        } else if (isNotEmpty(reportBo.getShopIdList())) {
            //带id
            list = reasonDao.shopReport(reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getShopIdList());
        } else {
            list = new ArrayList<>();
        }
        List<Report> reportList = dbResultToReportList(timeUnit, list);
        List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
        //写数据
        reports.forEach(data -> {
            try {
                Long shopId = data.getTmpId();
                Shop shop = ShopService.getInstance().findShopById(shopId);
                data.setY_zh(shop.getName_zh());
                data.setY_en(shop.getName_en());
            } catch (Exception e) {
                logger.error("e", e);
            }
        });
        //小数处理
        reports.forEach((r) -> {
            Double moneyDouble = showMoneyDouble(r.getValue());
            r.setValue(moneyDouble);
        });
        return reports;
    }

    /**
     * 统计商铺从营业到现在的金额，按照支付方式来分类
     * 统计小计部分
     *
     * @param shopId
     * @return
     */
    public Double sumCash(Long shopId, Integer payType) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return showDouble(orderDao.sumCash(shopId, shop.getOpenTime(), System.currentTimeMillis(), payType, true, false));
    }

    /**
     * 统计商铺从营业到现在的金额，按照支付方式来分类
     * 并且只是堂食
     * 统计小计部分
     *
     * @param shopId
     * @return
     */
    public Double sumTangShiCash(Long shopId, Integer payType) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return showDouble(orderDao.sumTangShiCash(shopId, shop.getOpenTime(), System.currentTimeMillis(), payType, false, true, false));
    }

    /**
     * 计算净营收
     *
     * @param shop
     * @return
     */
    public Double sumNetSale(Shop shop) {
        if (shop == null) {
            return showMoneyDouble(0d);
        }

        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        return showMoneyDouble(orderDao.sumNetSale(shop.getId(), shop.getOpenTime(), System.currentTimeMillis()));
    }

    /**
     * 计算净营收 + 销售税
     *
     * @param shop
     * @return
     */
    public double sumNetSaleWithTax(Shop shop) {
        if (shop == null) {
            return showMoneyDouble(0d);
        }

        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        return showMoneyDouble(orderDao.sumNetSaleWithTax(shop.getId(), shop.getOpenTime(), System.currentTimeMillis()));
    }

    /**
     * VIP訂單
     *
     * @param shop
     * @param payType
     * @return
     */
    public double sumVip(Shop shop, Integer payType) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        return showMoneyDouble(orderDao.sumVip(shop.getId(), shop.getOpenTime(), System.currentTimeMillis(), payType));
    }

    /**
     * 统计商铺从营业到现在的金额，按照支付方式来分类
     * 并且只是堂食
     * 统计小计部分
     *
     * @param shopId
     * @param payType
     * @return
     * @throws Exception
     */
    public Double sumTakeOutCash(Long shopId, Integer payType) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return showDouble(orderDao.sumTakeOutCash(shopId, shop.getOpenTime(), System.currentTimeMillis(), payType, false, true, false));
    }

    /**
     * * 统计商铺从营业到现在的服务费金额
     *
     * @param shopId
     * @return
     */
    public Double sumServiceFee(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.sumServiceFee(shopId, shop.getOpenTime(), System.currentTimeMillis(), true, true);
    }

    /**
     * * 统计商铺从营业到现在的包装费
     *
     * @param shopId
     * @return
     */
    public Double sumPackageFee(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.sumPackageFee(shopId, shop.getOpenTime(), System.currentTimeMillis(), true, true);
    }

    /**
     * 統計小費
     *
     * @param shopId
     * @return
     */
    public Double sumTipsFee(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.sumTipsFee(shopId, shop.getOpenTime(), System.currentTimeMillis());
    }

    /**
     * 消费税统计
     *
     * @param shopId
     * @return
     */
    public Double sumConsumptionTax(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.sumConsumptionTax(shopId, shop.getOpenTime(), System.currentTimeMillis());
    }

    /**
     * 统计商铺从营业到现在的外卖优惠费用
     *
     * @param shopId
     * @return
     * @throws Exception
     */
    public Double sumTakeOutDiscount(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.sumTakeOutFee(shopId, shop.getOpenTime(), System.currentTimeMillis(), true, true);
    }

    /**
     * 统计商铺从营业到现在的优惠卷使用的金额
     *
     * @param shopId
     * @return
     * @throws Exception
     */
    public Double sumDiscountFee(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.sumDiscountFee(shopId, shop.getOpenTime(), System.currentTimeMillis());
    }

    /**
     * 分店收到的现金
     *
     * @param shopId
     * @return
     */
    public Double sumUserCost(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.sumUserCost(shopId, shop.getOpenTime(), System.currentTimeMillis(), true, true);
    }


    /**
     * 已经发送到厨房，但是未支付的订单
     *
     * @param shopId
     * @return
     * @throws Exception
     */
    public double countSendToKitchenUnpaid(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return getDouble(orderDao.sumSendToKitchenUnpaid(shopId, shop.getOpenTime(), System.currentTimeMillis(), true, false, true, false, false));
    }

    /**
     * 堂食已经发送到厨房，但是未支付的订单
     *
     * @param shopId
     * @return
     * @throws Exception
     */
    public Double countSendToKitchenUnpaidForTangShi(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.sumSendToKitchenUnpaidForTangShi(shopId, shop.getOpenTime(), System.currentTimeMillis(), true, false, true, false, false);
    }

    /**
     * 外卖单里面，未支付的订单
     *
     * @param shopId
     * @return
     * @throws Exception
     */
    public Double sumSendToKitchenUnpaidForTakeOut(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.sumSendToKitchenUnpaidForTakeOut(shopId, shop.getOpenTime(), System.currentTimeMillis(), true, false, true, false, false);
    }

    /**
     * 已退款金额
     *
     * @param shopId
     * @return
     * @throws Exception
     */
    public Double returnCash(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.returnCash(shopId, shop.getOpenTime(), System.currentTimeMillis(), false, true, true);
    }

    /**
     * 堂食里面的退款金额
     *
     * @param shopId
     * @return
     * @throws Exception
     */
    public Double returnCashForTangShi(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.returnCashForTangShi(shopId, shop.getOpenTime(), System.currentTimeMillis(), false, true, true);
    }

    /**
     * 外卖里面的退款金额
     *
     * @param shopId
     * @returnUserService.java
     */
    public Double returnCashForTakeOut(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.returnCashForTakeOut(shopId, shop.getOpenTime(), System.currentTimeMillis(), false, true, true);
    }

    /**
     * 已经支付的订单里面的人数
     *
     * @param shopId
     * @return
     * @throws Exception
     */
    public Integer dinners(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.dinners(shopId, shop.getOpenTime(), System.currentTimeMillis(), true, true);
    }

    /**
     * 实际支付的订单数量
     *
     * @param shopId
     * @return
     * @throws Exception
     */
    public Integer orderNumber(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.orderNumber(shopId, shop.getOpenTime(), System.currentTimeMillis());
    }

    /**
     * 堂食的订单数量
     *
     * @param shopId
     * @return
     */
    public Integer tangShiOrderNumber(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.orderTangShiNumber(shopId, shop.getOpenTime(), System.currentTimeMillis(), true, true);
    }

    /**
     * 外卖的订单数量
     *
     * @param shopId
     * @return
     */
    public Integer takeOutOrderNumber(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.orderTakeOutNumber(shopId, shop.getOpenTime(), System.currentTimeMillis(), true, true);
    }

    /**
     * 删除的订单数量
     *
     * @param shopId
     * @return
     * @throws Exception
     */
    public int deleteOrderNumber(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return getInt(orderDao.deleteOrderNumber(shopId, shop.getOpenTime(), System.currentTimeMillis(), true, true, true));
    }

    /**
     * 查询删除的订单菜品数量
     *
     * @param shopId
     * @return
     */
    public int deleteOrderItemNumber(Long shopId) throws Exception {
        DeleteOrderItemDao deleteOrderItemDao = BeanUtil.getBean(DeleteOrderItemDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        long currentTimeMillis = System.currentTimeMillis();
        logger.info("shop id {} open time {} current time{}", shopId, shop.getOpenTime(), currentTimeMillis);
        return getInt(deleteOrderItemDao.countDeleteOrderItem(shopId, shop.getOpenTime(), currentTimeMillis));
    }

    /**
     * 计算销量
     *
     * @param shopId
     * @param startTime
     * @param endTime
     * @return
     */
    public ShopReport sumSalesAndCount(long shopId, long startTime, long endTime) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);

        //做两次统计，一次是金额的统计，一次是个数的统计
        //金额的统计是统计支付订单，个数的统计是统计总的订单
        List<Tuple> sumSaleTuple = orderDao.sumSale(shopId, startTime, endTime, false, true, false);
        ShopReport sumSaleReport = null;
        if (isNotEmpty(sumSaleTuple)) {
            sumSaleReport = new ShopReport();
            NativeResultProcessUtils.convertTupleToBean(sumSaleTuple.get(0), sumSaleReport);
        }

        List<Tuple> sumCountTuple = orderDao.sumCount(shopId, startTime, endTime, true);
        ShopReport sumCountReport = null;
        if (isNotEmpty(sumCountTuple)) {
            sumCountReport = new ShopReport();
            NativeResultProcessUtils.convertTupleToBean(sumCountTuple.get(0), sumCountReport);
        }

        ShopReport shopReport = new ShopReport();
        if (sumCountReport != null) {
            shopReport.setOrderNumber(sumCountReport.getOrderNumber());
        }

        if (sumSaleReport != null) {
            shopReport.setCash(sumSaleReport.getCash());
        }

        return shopReport;
    }

    /**
     * 统计已下单
     *
     * @param shopId
     * @param startConfirmTime
     * @param endConfirmTime
     * @return
     */
    public long countBusinessEndShow(long shopId, long startConfirmTime, long endConfirmTime) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        return getLong(orderDao.countBusinessEndShow(shopId, startConfirmTime, endConfirmTime, true, true));
    }

    /**
     * 统计已支付的订单
     *
     * @param shopId
     * @param startTime
     * @param endTime
     * @return
     */
    public long countPayedOrder(long shopId, long startTime, long endTime) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        return getLong(orderDao.countPayedOrder(shopId, startTime, endTime, true));
    }

    /**
     * 分组统计
     *
     * @param
     * @param startTime
     * @param endTime
     * @return
     */
    public List<ShopReport> sumSalesList(List<Long> shopIdList, long startTime, long endTime) throws Exception {

        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        //每5分钟统计
        List<Tuple> tupleList = orderDao.sumSaleUnit(shopIdList, startTime, endTime, DateUtil.ONE_MINUTE * 5, false, true, false);
        List<ShopReport> sumSaleReports = new ArrayList<>();
        for (Tuple tuple : tupleList) {
            ShopReport sumSaleReport = new ShopReport();
            NativeResultProcessUtils.convertTupleToBean(tuple, sumSaleReport);
            sumSaleReports.add(sumSaleReport);
        }

        List<ShopReport> sumSalesAndCountReportList = new ArrayList<>();
        for (Long shopId : shopIdList) {
            for (ShopReport sumSaleReport : sumSaleReports) {
                ShopReport shopReport = new ShopReport();
                if (equals(shopId, sumSaleReport.getShopId())) {
                    Shop shop = ShopService.getInstance().findShopById(shopId);
                    shopReport.setShopId(shopId);
                    shopReport.setName(shop.getName());
                    shopReport.setTimeShow(DateUtil.format(sumSaleReport.getTime() * DateUtil.ONE_MINUTE * 5, "HH:mm"));
                    shopReport.setBusinessStatus(shop.getBusinessStatus());
                    shopReport.setName_en(shop.getName_en());
                    shopReport.setName_zh(shop.getName_zh());
                    shopReport.setCash(sumSaleReport.getCash());
                    sumSalesAndCountReportList.add(shopReport);
                }
            }

        }

        return sumSalesAndCountReportList;
    }

    /**
     * 统计营业时间的外卖平台的订单量
     *
     * @param shopId
     * @return
     */
    public int countPlatOrderNumber(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return getInt(orderDao.countTakeOutPlat(shopId, shop.getOpenTime(), System.currentTimeMillis()));
    }

    /**
     * 统计营业时间的外卖平台的销售额
     *
     * @param shopId
     * @return
     */
    public Double sumPlatOrderCost(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        return orderDao.sumTakeOutPlat(shopId, shop.getOpenTime(), System.currentTimeMillis());
    }

    /**
     * 查询所有的已支付的支付订单
     *
     * @param shopId
     * @return
     */
    public List<Order> payedSubOrderList(Long shopId) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Shop shop = ShopService.getInstance().findShopById(shopId);
        List<Order> orderList = getList(orderDao.payedSubOrderList(shopId, shop.getOpenTime(), System.currentTimeMillis(), false, true, false));
        for (Order order : orderList) {
            commonService.dealFieldMapping(order, false);
        }
        return orderList;
    }

    /**
     * 添加删除的菜品到报表
     * 如果没有被打印过，那么该菜将不会被添加
     *
     * @param orderItemId
     * @param orderInDb
     */
    public void addDeleteOrderItem(Long orderItemId, Order orderInDb) throws Exception {
        if (!OrderService.getInstance().isOrderItemPrinted(orderInDb, orderItemId)) {
            logger.info("order item not deleted");
            return;
        }

        logger.info("will add order item {} to print list", orderItemId);
        OrderItem orderItem = OrderService.getInstance().filterOrderItemList(orderInDb, orderItemId);
        DeleteOrderItem deleteOrderItem = new DeleteOrderItem();
        deleteOrderItem.setShopId(orderInDb.getShopId());
        deleteOrderItem.setOrderItemId(orderItemId);
        deleteOrderItem.setSendKitchen(orderInDb.getSendKitchen());
        //特别菜单独处理
        if (equals(orderItem.getItemId(),SPECIAL_ITEM)){
            deleteOrderItem.setOrderItemName_en(SPECIAL_ITEM_NAME_EN);
            deleteOrderItem.setOrderItemName_zh(SPECIAL_ITEM_NAME_ZH);
        }else {
            deleteOrderItem.setOrderItemName(orderItem.getItemName());
            deleteOrderItem.setOrderItemName_en(orderItem.getItemName_en());
            deleteOrderItem.setOrderItemName_zh(orderItem.getItemName_en());
        }
        deleteOrderItem.setPrice(orderItem.getItemTotalCost());
        deleteOrderItem.setCountNumber(orderItem.getCount());
        deleteOrderItem.setItemId(orderItem.getItemId());

        commonService.createObject(deleteOrderItem);

        //添加统计名称
        ShopSearchItemService.getInstance().addDeleteOrderItem(deleteOrderItem);
    }

    /**
     * 添加一个被删除的菜
     *
     * @param orderItemId
     * @param orderInDb
     */
    public void cutOneOrderItem(Long orderItemId, Order orderInDb) throws Exception {
        if (!OrderService.getInstance().isOrderItemPrinted(orderInDb, orderItemId)) {
            logger.info("order item not deleted");
            return;
        }

        logger.info("will add order item {} to print list", orderItemId);
        DeleteOrderItem deleteOrderItem = new DeleteOrderItem();
        deleteOrderItem.setShopId(orderInDb.getShopId());
        deleteOrderItem.setOrderItemId(orderItemId);
        deleteOrderItem.setCountNumber(1);

        commonService.createObject(deleteOrderItem);

        //添加统计名称
        ShopSearchItemService.getInstance().addDeleteOrderItem(deleteOrderItem);
    }

    /**
     * 获取报表数据
     *
     * @param reportBo
     * @return
     */
    public List<Report> getReportData(ReportBo reportBo) throws Exception {
        switch (reportBo.getType().intValue()) {
            case 1:
                return catalogReport(reportBo);
            case 2:
                return itemReport(reportBo);
            case 3:
                return payTypeReport(reportBo);
            case 4:
                return orderTypeReport(reportBo);
            case 5:
                return waiterReport(reportBo);
            case 6:
                return discountTicketReport(reportBo);
            case 7:
                return feedbackReport(reportBo);
            case 8:
                return reasonReport(reportBo);
            case 9:
                return shopReport(reportBo);
            //会员性别统计
            case 10:
                return customerSexReport(reportBo);
            //会员年龄统计
            case 11:
                return customerAgeReport(reportBo);
            //会员客单价统计
            case 12:
                return customerUserCostReport(reportBo);
            //新客，熟客统计
            case 13:
                return newCustomerReport(reportBo);
            //会员等级统计
            case 14:
                return customerLevelReport(reportBo);
            //VIP会员消费统计
            case 15:
                return vipCustomerOrder(reportBo);
            //VIP订单统计
            case 16:
                return customerVipOrder(reportBo);
            case 17:
                //邮件续费VIP统计，传companyId
                return customerRenewVipOrder(reportBo);
            case 18:
                //统计删除的菜品或套餐的份数及金额
                return deleteItemReport(reportBo);

            default:
        }

        return new ArrayList<>();
    }


    /**
     * 删除菜品和套餐的统计
     *
     * @param reportBo
     * @return
     */
    private List<Report> deleteItemReport(ReportBo reportBo) throws Exception {
        DeleteOrderItemDao deleteOrderItemDao = BeanUtil.getBean(DeleteOrderItemDao.class);
        ReportBo reportBoClone = (ReportBo) ClassUtil.clone(reportBo);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        List<Report> totalDeleteAmountOrQtyList = null;
        //统计
        if (!isNotEmpty(reportBo.getTimeUnit())) {
            if (equals(reportBo.getAmountQtyType(), BY_AMOUNT_FIND)) {
                //按金额
                totalDeleteAmountOrQtyList = deleteItemTotalAmount(reportBo);
            } else {
                //按数量
                totalDeleteAmountOrQtyList = deleteItemTotalQty(reportBo);
            }

            //国际化处理
            for (Report report : getList(totalDeleteAmountOrQtyList)) {
                Long catalogId = report.getTmpId();
                if (isNotEmpty(catalogId) && report.getTmpId() > 0) {
                    Item itemInDb = null;
                    try {
                        itemInDb = ItemService.getInstance().findItem(catalogId);
                    } catch (Exception e) {
                    }
                    if (itemInDb != null) {
                        if (isNotEmpty(itemInDb.getName())) {
                            report.setY(itemInDb.getName());
                        }
                        if (isNotEmpty(itemInDb.getName_zh())) {
                            report.setY_zh(itemInDb.getName_zh());
                        }
                        if (isNotEmpty(itemInDb.getName_en())) {
                            report.setY_en(itemInDb.getName_en());
                        }
                    }
                }
            }
            totalDeleteAmountOrQtyList = itemOrCatalogMoneyOrQtySort(totalDeleteAmountOrQtyList, reportBoClone);

            //特别菜处理
            for (Report report : totalDeleteAmountOrQtyList) {
                if (equals(report.getTmpId(), SPECIAL_ITEM)) {
                    report.setY_zh(SPECIAL_ITEM_NAME_ZH);
                    report.setY_en(SPECIAL_ITEM_NAME_EN);
                }
            }
            //小数处理
            totalDeleteAmountOrQtyList.forEach((r) -> {
                Double moneyDouble = showMoneyDouble(r.getValue());
                r.setValue(moneyDouble);
            });

            return totalDeleteAmountOrQtyList;

        }

        if (equals(reportBo.getAmountQtyType(), BY_AMOUNT_FIND)){
            if (isNotEmpty(reportBo.getNameZhTypeList())) {
                //中文
                List<Tuple> deleteItemTupleList = deleteOrderItemDao.idDeleteTotalAmountReportZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getNameZhTypeList());
                totalDeleteAmountOrQtyList = dbResultToReportList(timeUnit, deleteItemTupleList);
            }

            if (isNotEmpty(reportBo.getNameEnTypeList())){
                //英文
                List<Tuple> deleteItemTupleList = deleteOrderItemDao.idDeleteTotalAmountReportEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getNameEnTypeList());
                totalDeleteAmountOrQtyList = dbResultToReportList(timeUnit, deleteItemTupleList);
            }
            if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())){

                //不带名称集合查询
                List<Tuple> deleteItemTupleList = deleteOrderItemDao.deleteTotalAmountReport(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat);
                totalDeleteAmountOrQtyList = dbResultToReportList(timeUnit, deleteItemTupleList);
            }
        }

        if (equals(reportBo.getAmountQtyType(), BY_QTY_FIND)){

            if (isNotEmpty(reportBo.getNameZhTypeList())) {
                //中文
                List<Tuple> deleteItemTupleList = deleteOrderItemDao.idDeleteTotalQtyReportZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getNameZhTypeList());
                totalDeleteAmountOrQtyList = dbResultToReportList(timeUnit, deleteItemTupleList);
            }

            if (isNotEmpty(reportBo.getNameEnTypeList())){
                //英文
                List<Tuple> deleteItemTupleList = deleteOrderItemDao.idDeleteTotalQtyReportEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getNameEnTypeList());
                totalDeleteAmountOrQtyList = dbResultToReportList(timeUnit, deleteItemTupleList);
            }
            if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())){

                //不带名称集合查询
                List<Tuple> deleteItemTupleList = deleteOrderItemDao.deleteTotalQtyReport(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), timeFormat);
                totalDeleteAmountOrQtyList = dbResultToReportList(timeUnit, deleteItemTupleList);
            }
        }


        //处理国际化
        for (Report report : getList(totalDeleteAmountOrQtyList)) {
            Long catalogId = report.getTmpId();
            if (isNotEmpty(catalogId) && report.getTmpId() > 0) {

                Item itemInDb = null;
                try {
                    itemInDb = ItemService.getInstance().findItem(catalogId);
                } catch (Exception e) {
                }
                if (itemInDb != null) {
                    if (isNotEmpty(itemInDb.getName())) {
                        report.setY(itemInDb.getName());
                    }
                    if (isNotEmpty(itemInDb.getName_zh())) {
                        report.setY_zh(itemInDb.getName_zh());
                    }
                    if (isNotEmpty(itemInDb.getName_en())) {
                        report.setY_en(itemInDb.getName_en());
                    }
                }
            }
        }

        //给年月日选项排序
        totalDeleteAmountOrQtyList = itemOrCatalogMoneyOrQtySort(getList(totalDeleteAmountOrQtyList), reportBoClone);

        List<Item> itemList = new ArrayList<>();
        for (Report report : totalDeleteAmountOrQtyList) {
            //特别菜单独处理
            if (equals(report.getTmpId(), SPECIAL_ITEM)) {
                report.setY_zh(SPECIAL_ITEM_NAME_ZH);
                report.setY_en(SPECIAL_ITEM_NAME_EN);
            } else {
                Optional<Item> itemOption = ItemService.getInstance().findItemOption(report.getTmpId(), itemList);
                if (itemOption.isPresent()) {
                    Item item = itemOption.get();
                    report.setY_zh(item.getName_zh());
                    report.setY_en(item.getName_en());
                }
            }
        }

        //小数处理
        totalDeleteAmountOrQtyList.forEach((r) -> {
            Double moneyDouble = showMoneyDouble(r.getValue());
            r.setValue(moneyDouble);
        });

        return totalDeleteAmountOrQtyList;
    }

    /**
     * 删除菜品的数量总计
     *
     * @param reportBo
     * @return
     */

    private List<Report> deleteItemTotalQty(ReportBo reportBo) {

        DeleteOrderItemDao deleteOrderItemDao = BeanUtil.getBean(DeleteOrderItemDao.class);

        List<Tuple> tupleArrayList = null;

        if (isNotEmpty(reportBo.getNameZhTypeList())) {
            //中文
            tupleArrayList = deleteOrderItemDao.idDeleteTotalQtyZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getNameZhTypeList());

        }

        if (isNotEmpty(reportBo.getNameEnTypeList())){
            //英文
            tupleArrayList = deleteOrderItemDao.idDeleteTotalQtyEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getNameZhTypeList());

        }
        if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())){

            //不带名称集合查询
            tupleArrayList = deleteOrderItemDao.deleteTotalQty(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime());

        }



        List<Report> deleteTotalReportList = tupleArrayList.stream().map(p -> {
            Report report = new Report();
            NativeResultProcessUtils.convertTupleToBean(p, report);
            return report;
        }).collect(Collectors.toList());

        return deleteTotalReportList;
    }


    /**
     * 删除菜品的金额总计
     *
     * @param reportBo
     * @return
     */
    private List<Report> deleteItemTotalAmount(ReportBo reportBo) {
        DeleteOrderItemDao deleteOrderItemDao = BeanUtil.getBean(DeleteOrderItemDao.class);

        List<Tuple> tupleArrayList = null;

        if (isNotEmpty(reportBo.getNameZhTypeList())) {
            //中文
            tupleArrayList = deleteOrderItemDao.idDeleteTotalAmountZh(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getNameZhTypeList());

        }

        if (isNotEmpty(reportBo.getNameEnTypeList())){
            //英文
            tupleArrayList = deleteOrderItemDao.idDeleteTotalAmountEn(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getNameEnTypeList());

        }
        if (isEmpty(reportBo.getNameZhTypeList()) && isEmpty(reportBo.getNameEnTypeList())){

            //不带名称集合查询
            tupleArrayList = deleteOrderItemDao.deleteTotalAmount(reportBo.getShopIdList(), reportBo.getStartTime(), reportBo.getEndTime());

        }


        List<Report> deleteTotalReportList = tupleArrayList.stream().map(p -> {
            Report report = new Report();
            NativeResultProcessUtils.convertTupleToBean(p, report);
            return report;
        }).collect(Collectors.toList());

        return deleteTotalReportList;
    }

    /**
     * 数据导出
     *
     * @param reportBo
     * @return
     */
    public File exportData(ReportBo reportBo) throws Exception {
        List<Report> reportList = getReportData(reportBo);
        //将reportList转化成二维数组
        List<List<Object>> dataList = reportList.stream().map(p -> {
            List<Object> objectList = new ArrayList<>();
            objectList.add(p.getX());
            if (isNotEmpty(p.getY_zh()) || isNotEmpty(p.getY_en())) {
                objectList.add(String.format("%s/%s", p.getY_zh(), p.getY_en()));
            } else {
                objectList.add(String.format("%s", p.getY()));
            }

            objectList.add(p.getValue());
            return objectList;
        }).collect(Collectors.toList());

        //报表数据，转化成excel数据
        List<String> titleList = Arrays.asList("x", "y", "value");
        File file = ExcelUtil.getInstance().exportExcel(titleList, dataList);

        //将文件上传到指定的桶
        ObjectService.getInstance().uploadObject(file);

        return file;
    }

    /**
     * 依次删除数据
     *
     * @param order
     */
    public void deleteRelatedReportData(Order order) throws Exception {
        List<Order> orderList = OrderService.getInstance().findOrderByParentId(order.getId(), order.getShopId());

        deleteRelatedReportDataSingle(order);
        for (Order subOrder : orderList) {
            deleteRelatedReportDataSingle(subOrder);
        }

    }

    /**
     * 删除相关的订单数据
     *
     * @param order
     */
    public void deleteRelatedReportDataSingle(Order order) throws Exception {
        deleteReportData(order.getId(), OrderCatalogMapping.class);
        deleteReportData(order.getId(), OrderItemMapping.class);
        deleteReportData(order.getId(), OrderPayTypeMapping.class);
        deleteReportData(order.getId(), OrderTypeMapping.class);
        deleteReportData(order.getId(), OrderWaiterMapping.class);
        deleteReportData(order.getId(), OrderDiscountTicketMapping.class);
        deleteReportData(order.getId(), Feedback.class);
        deleteReportData(order.getId(), Reason.class);
    }

    /**
     * 删除报表数据
     *
     * @param orderId
     * @param tclass
     */
    public <T extends AbstractEntity> void deleteReportData(Long orderId, Class<T> tclass) throws Exception {
        T o = (T) tclass.newInstance();
        Field orderIdField = ClassUtil.getInstance().getField(tclass, "orderId");
        Field beRequestField = ClassUtil.getInstance().getField(tclass, "beRequest");
        orderIdField.set(o, orderId);
        beRequestField.set(o, true);
        commonService.delete(o, false, null);
    }

    /**
     * 会员性别报告
     *
     * @param reportBo
     * @return
     */
    public List<Report> customerSexReport(ReportBo reportBo) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        //不需要top3,让IdTypeList不为空即可
        List<Long> idTypeList = new ArrayList<>();
        idTypeList.add(1L);
        reportBo.setIdTypeList(idTypeList);
        List<Tuple> list;
        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {
            list = orderDao.sexReportTotal(reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getShopIdList());
            List<Report> reportList = dbResultToReportList(timeUnit, list);
            List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
            //重新根据catalogId来写中英文
            for (Report report : reports) {
                long sex = report.getTmpId();
                if (sex == 1) {
                    report.setY("男");
                    report.setY_zh("男");
                    report.setY_en("Male");
                }
                if (sex == 2) {
                    report.setY("女");
                    report.setY_zh("女");
                    report.setY_en("Female");
                }
            }
            //小数处理
            reports.forEach((r) -> {
                Double moneyDouble = showMoneyDouble(r.getValue());
                r.setValue(moneyDouble);
            });
            return reports;
        }
        //年月日
        list = orderDao.sexReport(reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getShopIdList());
        List<Report> reportList = dbResultToReportList(timeUnit, list);
        List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
        //重新根据catalogId来写中英文
        for (Report report : reports) {
            long sex = report.getTmpId();
            if (sex == 1) {
                report.setY("男");
                report.setY_zh("男");
                report.setY_en("Male");
            } else {
                report.setY("女");
                report.setY_zh("女");
                report.setY_en("Female");
            }
        }

        return reports;
    }

    /**
     * 会员年龄报告
     *
     * @param reportBo
     * @return
     */
    public List<Report> customerAgeReport(ReportBo reportBo) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        //不需要top3,让IdTypeList不为空即可
        List<Long> idTypeList = new ArrayList<>();
        idTypeList.add(1L);
        reportBo.setIdTypeList(idTypeList);
        List<Tuple> list;
        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {
            list = orderDao.ageReportTotal(reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getShopIdList());
            List<Report> reportList = dbResultToReportList(timeUnit, list);
            List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
            //重新根据catalogId来写中英文
            for (Report report : reports) {
                long age = report.getTmpId();
                if (age == 10) {
                    report.setY_zh("20歲以下");
                    report.setY_en("Under 20 years old");
                } else if (age == 20) {
                    report.setY_zh("20歲~29歲");
                    report.setY_en("20 to 29 years old");
                } else if (age == 30) {
                    report.setY_zh("30歲~39歲");
                    report.setY_en("30 to 39 years old");
                } else {
                    report.setY_zh("40歲以上");
                    report.setY_en("40 years old and above");
                }
            }
            //小数处理
            reports.forEach((r) -> {
                Double moneyDouble = showMoneyDouble(r.getValue());
                r.setValue(moneyDouble);
            });
            return reports;
        }
        //年月日
        list = orderDao.ageReport(reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getShopIdList());
        List<Report> reportList = dbResultToReportList(timeUnit, list);
        List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
        //重新根据catalogId来写中英文
        for (Report report : reports) {
            long age = report.getTmpId();
            if (age == 10) {
                report.setY_zh("20歲以下");
                report.setY_en("Under 20 years old");
            } else if (age == 20) {
                report.setY_zh("20歲~29歲");
                report.setY_en("20 to 29 years old");
            } else if (age == 30) {
                report.setY_zh("30歲~39歲");
                report.setY_en("30 to 39 years old");
            } else {
                report.setY_zh("40歲以上");
                report.setY_en("40 years old and above");
            }
        }
        return reports;
    }

    /**
     * 会员单价查询，求平均值
     *
     * @param reportBo
     * @return
     */
    public List<Report> customerUserCostReport(ReportBo reportBo) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        //不需要top3,让IdTypeList不为空即可
        List<Long> idTypeList = new ArrayList<>();
        idTypeList.add(1L);
        reportBo.setIdTypeList(idTypeList);
        List<Tuple> list;
        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {
            list = orderDao.customerPerCostReportTotal(reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getShopIdList());
            List<Report> reportList = dbResultToReportList(timeUnit, list);
            for (Report report : reportList) {
                report.setY_zh("客單價");
                report.setY_en("Average spend per customer");
            }
            //小数处理
            reportList.forEach((r) -> {
                Double moneyDouble = showMoneyDouble(r.getValue());
                r.setValue(moneyDouble);
            });
            return reportList;
        }
        //年月日
        list = orderDao.customerPerCostReport(reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getShopIdList());
        List<Report> reportList = dbResultToReportList(timeUnit, list);
        for (Report report : reportList) {
            report.setY_zh("客單價");
            report.setY_en("Average spend per customer");
        }
        return reportList;
    }

    /**
     * 新会员的报告
     *
     * @param reportBo
     * @return
     */
    public List<Report> newCustomerReport(ReportBo reportBo) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        //不需要top3,让IdTypeList不为空即可
        List<Long> idTypeList = new ArrayList<>();
        idTypeList.add(1L);
        reportBo.setIdTypeList(idTypeList);
        List<Tuple> list;
        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {
            list = orderDao.newCustomerReportTotal(reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getShopIdList());
            List<Report> reportList = dbResultToReportList(timeUnit, list);

            for (Report report : reportList) {
                Long tmpId = report.getTmpId();
                if (getLong(tmpId) == 0) {
                    report.setY_zh("新客");
                    report.setY_en("New Customer");
                } else {
                    report.setY_zh("熟客");
                    report.setY_en("Existing Customer");
                }
            }
            //小数处理
            reportList.forEach((r) -> {
                Double moneyDouble = showMoneyDouble(r.getValue());
                r.setValue(moneyDouble);
            });
            return reportList;
        }
        //年月日
        list = orderDao.newCustomerReport(reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getShopIdList());
        List<Report> reportList = dbResultToReportList(timeUnit, list);

        for (Report report : reportList) {
            Long tmpId = report.getTmpId();
            if (getLong(tmpId) == 0) {
                report.setY_zh("新客");
                report.setY_en("New Customer");
            } else {
                report.setY_zh("熟客");
                report.setY_en("Existing Customer");
            }
        }
        return reportList;
    }

    /**
     * 会员等级报告
     *
     * @param reportBo
     * @return
     */
    public List<Report> customerLevelReport(ReportBo reportBo) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        //不需要top3,让IdTypeList不为空即可
        List<Long> idTypeList = new ArrayList<>();
        idTypeList.add(1L);
        reportBo.setIdTypeList(idTypeList);
        List<Tuple> list;
        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {
            list = orderDao.customerLevelReportTotal(reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getShopIdList());
            List<Report> reportList = dbResultToReportList(timeUnit, list);
            List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
            for (Report report : reports) {
                Long tmpId = report.getTmpId();
                Optional<VipLevel> vipLevelOptional = CustomerService.getInstance().findVipLevelOption(tmpId);
                if (!vipLevelOptional.isPresent()) {
                    report.setY_zh("會員等級已刪除");
                    report.setY_en("The Member Level has been deleted");
                } else {
                    VipLevel vipLevel = vipLevelOptional.get();
                    report.setY_zh(vipLevel.getName_zh());
                    report.setY_en(vipLevel.getName_en());
                }
            }
            //小数处理
            reports.forEach((r) -> {
                Double moneyDouble = showMoneyDouble(r.getValue());
                r.setValue(moneyDouble);
            });
            return reports;
        }
        //年月日
        list = orderDao.customerLevelReport(reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getShopIdList());
        List<Report> reportList = dbResultToReportList(timeUnit, list);
        List<Report> reports = itemOrCatalogMoneyOrQtySort(reportList, reportBo);
        for (Report report : reports) {
            Long tmpId = report.getTmpId();
            Optional<VipLevel> vipLevelOptional = CustomerService.getInstance().findVipLevelOption(tmpId);
            if (!vipLevelOptional.isPresent()) {
                report.setY_zh("會員等級已刪除");
                report.setY_en("The Member Level has been deleted");
            } else {
                VipLevel vipLevel = vipLevelOptional.get();
                report.setY_zh(vipLevel.getName_zh());
                report.setY_en(vipLevel.getName_en());
            }
        }

        return reports;
    }

    /**
     * VIP会员消费
     *
     * @param reportBo
     * @return
     */
    public List<Report> vipCustomerOrder(ReportBo reportBo) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        //不需要top3,让IdTypeList不为空即可
        List<Long> idTypeList = new ArrayList<>();
        idTypeList.add(1L);
        reportBo.setIdTypeList(idTypeList);
        List<Tuple> list;
        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {
            List<Report> allReportList = new ArrayList<>();
            {
                list = orderDao.vipCustomerOrderCountTotal(reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getShopIdList());
                List<Report> reportList = dbResultToReportList(timeUnit, list);
                for (Report report : reportList) {
                    report.setY_zh("VIP消費次數");
                    report.setY_en("VIP Visits");
                }
                allReportList.addAll(reportList);
            }

            {
                list = orderDao.vipCustomerOrderListTotal(reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getShopIdList());
                List<Report> reportList = dbResultToReportList(timeUnit, list);
                for (Report report : reportList) {
                    report.setY_zh("VIP消费");
                    report.setY_en("VIP Spending");
                }
                allReportList.addAll(reportList);
            }
            return allReportList;
        }
        //年月日
        List<Report> allReportList = new ArrayList<>();
        {
            list = orderDao.vipCustomerOrderCount(reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getShopIdList());
            List<Report> reportList = dbResultToReportList(timeUnit, list);
            for (Report report : reportList) {
                report.setY_zh("VIP消費次數");
                report.setY_en("VIP Visits");
            }
            allReportList.addAll(reportList);
        }

        {
            list = orderDao.vipCustomerOrderList(reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getShopIdList());
            List<Report> reportList = dbResultToReportList(timeUnit, list);
            for (Report report : reportList) {
                report.setY_zh("VIP消费");
                report.setY_en("VIP Spending");
            }

            allReportList.addAll(reportList);
        }
        return allReportList;
    }

    /**
     * VIP会员消费
     *
     * @param reportBo
     * @return
     */
    public List<Report> customerVipOrder(ReportBo reportBo) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        //不需要top3,让IdTypeList不为空即可
        List<Long> idTypeList = new ArrayList<>();
        idTypeList.add(1L);
        reportBo.setIdTypeList(idTypeList);
        List<Tuple> list;
        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {
            List<Report> allReportList = new ArrayList<>();

            {
                list = orderDao.customerVipOrderCountTotal(reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getShopIdList());
                List<Report> reportList = dbResultToReportList(timeUnit, list);
                for (Report report : reportList) {
                    report.setY_zh("VIP續費人數");
                    report.setY_en("No. of VIP Renewed");
                }

                allReportList.addAll(reportList);
            }

            {
                list = orderDao.customerVipOrderSumTotal(reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getShopIdList());
                List<Report> reportList = dbResultToReportList(timeUnit, list);
                for (Report report : reportList) {
                    report.setY_zh("VIP會員費");
                    report.setY_en("VIP Fee");
                }
                allReportList.addAll(reportList);
            }

            return allReportList;
        }
        List<Report> allReportList = new ArrayList<>();
        {
            list = orderDao.customerVipOrderCount(reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getShopIdList());
            List<Report> reportList = dbResultToReportList(timeUnit, list);
            for (Report report : reportList) {
                report.setY_zh("VIP續費人數");
                report.setY_en("No. of VIP Renewed");
            }

            allReportList.addAll(reportList);
        }

        {
            list = orderDao.customerVipOrderSum(reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getShopIdList());
            List<Report> reportList = dbResultToReportList(timeUnit, list);
            for (Report report : reportList) {
                report.setY_zh("VIP會員費");
                report.setY_en("VIP Fee");
            }
            allReportList.addAll(reportList);
        }
        return allReportList;
    }

    /**
     * 邮件自动续费邮件
     *
     * @param reportBo
     * @return
     */
    public List<Report> customerRenewVipOrder(ReportBo reportBo) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Long timeUnit = getTimeUnit(reportBo);
        String timeFormat = getTimeFormat(timeUnit);
        //不需要top3,让IdTypeList不为空即可
        List<Long> idTypeList = new ArrayList<>();
        idTypeList.add(1L);
        reportBo.setIdTypeList(idTypeList);

        List<Tuple> list;
        //总计
        if (!isNotEmpty(reportBo.getTimeUnit())) {
            List<Report> allReportList = new ArrayList<>();
            {
                list = orderDao.customerVipOrderRenewCountTotal(reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getCompanyId());
                List<Report> reportList = dbResultToReportList(timeUnit, list);
                for (Report report : reportList) {
                    report.setY_zh("VIP人數");
                    report.setY_en("No. of VIP");
                }

                allReportList.addAll(reportList);
            }

            {
                list = orderDao.customerVipOrderRenewSumTotal(reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getCompanyId());
                List<Report> reportList = dbResultToReportList(timeUnit, list);
                for (Report report : reportList) {
                    report.setY_zh("VIP自動續費");
                    report.setY_en("VIP Auto Renewal");
                }
                allReportList.addAll(reportList);
            }
            return allReportList;
        }
        //年月日
        List<Report> allReportList = new ArrayList<>();
        {
            list = orderDao.customerVipOrderRenewCount(reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getCompanyId());
            List<Report> reportList = dbResultToReportList(timeUnit, list);
            for (Report report : reportList) {
                report.setY_zh("VIP人數");
                report.setY_en("No. of VIP");
            }
            allReportList.addAll(reportList);
        }
        {
            list = orderDao.customerVipOrderRenewSum(reportBo.getStartTime(), reportBo.getEndTime(), timeFormat, reportBo.getCompanyId());
            List<Report> reportList = dbResultToReportList(timeUnit, list);
            for (Report report : reportList) {
                report.setY_zh("VIP自動續費");
                report.setY_en("VIP Auto Renewal");
            }
            allReportList.addAll(reportList);
        }
        return allReportList;
    }

    /**
     * 查询这一段时间的订单的总计
     *
     * @param startTime
     * @param endTime
     * @return
     */
    public double sumTotal(List<Long> shopIdList, Long startTime, Long endTime) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Double sumSale = orderDao.sumSale(shopIdList, startTime, endTime, true, true, false);
        return getDouble(sumSale);
    }

    /**
     * 指定时间范围内的订单的价格的平均值
     *
     * @param shopIdList
     * @param startTime
     * @param endTime
     * @return
     */
    public double avgOrder(List<Long> shopIdList, Long startTime, Long endTime, double days) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        logger.info("shopId list is {}, start time {}, end time {}", shopIdList, startTime, endTime);
        return getDouble(orderDao.avgSale(shopIdList, startTime, endTime, days));
    }

    /**
     * 计算所有已经支付完成的订单数量
     * 按照父订单的来统计
     *
     * @param shopIdList
     * @param startTime
     * @param endTime
     * @return
     */
    public int countCompleteParentOrder(List<Long> shopIdList, Long startTime, Long endTime) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        return getInt(orderDao.countCompleteParentOrder(shopIdList, startTime, endTime));
    }

    /**
     * TOP3的支付方式的支付金额
     *
     * @param shopIdList
     * @param startTime
     * @param endTime
     * @return
     */
    public List<Report> top3PayType(List<Long> shopIdList, Long startTime, Long endTime) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        List<Tuple> tuples = orderDao.topNPayType(shopIdList, startTime, endTime);
        List<Report> payTypeReportList = tuples.stream().map(tuple -> {
            Report report = new Report();
            NativeResultProcessUtils.convertTupleToBean(tuple, report);
            return report;
        }).collect(Collectors.toList());

        return CollectionUtil.getInstance().take(payTypeReportList, 3);
    }

    /**
     * 所有支付方式的总和
     *
     * @param shopIdList
     * @param startTime
     * @param endTime
     * @return
     */
    public double totalPayType(List<Long> shopIdList, Long startTime, Long endTime) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        Double payTypeTotal = orderDao.totalPayType(shopIdList, startTime, endTime);

        return getDouble(payTypeTotal);
    }

    /**
     * 查询指定时间段已经支付的父订单
     *
     * @param shopId
     * @param startTime
     * @param endTime
     * @return
     */
    public List<Order> findPayedOrder(Long shopId, Long startTime, Long endTime) {
        Order order = new Order();
        order.setShopId(shopId);
        order.setParentOrder(true);
        order.setStatus(ORDER_STATUS_END);
        order.setStartCreateTime(startTime);
        order.setEndCreateTime(endTime);
        return commonService.searchAll(order);
    }

    /**
     * 查询这段时间内的所有订单
     *
     * @param shopIdList
     * @param startTime
     * @param endTime
     * @return
     */
    public List<Order> findAllPayedOrder(List<Long> shopIdList, Long startTime, Long endTime) {
        List<Order> orderList = shopIdList.stream().flatMap(shopId -> {
            return findPayedOrder(shopId, startTime, endTime).stream();
        }).collect(Collectors.toList());

        logger.info("all order size is {}", orderList);
        return orderList;
    }

    /**
     * TOP 5的菜
     *
     * @param orderList
     * @return
     */
    public List<OrderItem> top5Item(List<Order> orderList) {
        List<OrderItem> orderItemList = orderList.stream().flatMap(order -> getList(order.getOrderItemDetailList()).stream()).collect(Collectors.toList());

        Map<String, List<OrderItem>> itemIdMap = orderItemList.stream().collect(Collectors.groupingBy(orderItem -> {
            return orderItem.getItemName_zh();
        }));


        orderItemList = itemIdMap.entrySet().stream().map(entity -> {
            List<OrderItem> orderItemListTmp = entity.getValue();
            OrderItem orderItem = new OrderItem();
            BeanUtils.copyProperties(orderItemListTmp.get(0), orderItem);

            double itemCost = orderItemListTmp.stream().mapToDouble(item -> getDouble(item.getItemPrice()) * getInt(item.getCount())).sum();
            int itemCount = orderItemListTmp.stream().mapToInt(item -> getInt(item.getCount())).sum();
            //计算总和的金额以及数量
            orderItem.setReportValue(itemCost);
            orderItem.setCount(itemCount);
            return orderItem;
        }).collect(Collectors.toList());

        //再处理套餐里面的钱，以及数量
        List<OrderItem> itemListInSetMenu = calOrderItemCashAndCountInSetMenu(orderList, (item) -> item.getName_en());
        //合并钱以及金额
        orderItemList = mergeOrderItem(orderItemList, itemListInSetMenu, (orderItem, orderItemInSetMenu) -> equals(orderItem.getItemName_en(), orderItemInSetMenu.getItemName_en()));

        //按照金额排序
        orderItemList = orderItemList.stream().sorted(Comparator.comparing(OrderItem::getReportValue).reversed()).collect(Collectors.toList());
        orderItemList.forEach(p -> p.setItemDetailList(null));
        orderItemList.forEach(p -> p.setDetailJson(null));
        orderItemList.forEach(p -> p.setSetMenuOneItemList(null));
        return CollectionUtil.getInstance().take(orderItemList, 5);
    }

    /**
     * 计算订单里面的套餐的菜的价格以及份数
     *
     * @param orderList
     * @return
     */
    public List<OrderItem> calOrderItemCashAndCountInSetMenu(List<Order> orderList, Function<Item, String> filterItemFunction) {
        List<OrderItem> orderItemList = orderList.stream().flatMap(order -> getList(order.getOrderItemDetailList()).stream()).collect(Collectors.toList());
        orderItemList = orderItemList.stream().filter(orderItem -> getBoolean(orderItem.getSetMenu())).collect(Collectors.toList());
        List<SetMenuOneItem> setMenuOneItemList = orderItemList.stream().flatMap(orderItem -> orderItem.getSetMenuOneItemList().stream()).collect(Collectors.toList());
        List<Item> itemList = setMenuOneItemList.stream().flatMap(item -> getList(item.getItemList()).stream()).collect(Collectors.toList());
        itemList = itemList.stream().filter(item -> item != null && isNotEmpty(item.getName_en()) && isNotEmpty(item.getCatalogName_en())).collect(Collectors.toList());

        Map<String, List<Item>> itemMap = itemList.stream().collect(Collectors.groupingBy(item -> {
            return filterItemFunction.apply(item);
        }));

        return itemMap.entrySet().stream().map(entity -> {
            List<Item> itemTmpList = entity.getValue();
            Item item = itemTmpList.get(0);
            OrderItem orderItem = new OrderItem();
            orderItem.setItemName_zh(item.getName_zh());
            orderItem.setItemName_en(item.getName_en());
            orderItem.setItemId(item.getId());

            //写品类ID以及名称
            orderItem.setCatalogId(item.getCatalogId());
            orderItem.setCatalogName_en(item.getCatalogName_en());
            orderItem.setCatalogName_zh(item.getCatalogName_zh());

            //金额以有份数
            double itemCost = itemTmpList.stream().mapToDouble(itemP -> ItemService.getInstance().calItemInSetMenuPrice(itemP)).sum();
            int itemCount = itemTmpList.stream().mapToInt(itemP -> ItemService.getInstance().calItemCountInSetMenu(itemP)).sum();

            orderItem.setReportValue(itemCost);
            orderItem.setCount(itemCount);
            return orderItem;
        }).collect(Collectors.toList());
    }

    /**
     * 将普通菜与套餐里面的菜合并
     *
     * @param orderItemList
     * @param orderItemInSetMenuList
     * @return
     */
    public List<OrderItem> mergeOrderItem(List<OrderItem> orderItemList, List<OrderItem> orderItemInSetMenuList, BiFunction<OrderItem, OrderItem, Boolean> itemFilterFunction) {
        if (isEmpty(orderItemInSetMenuList)) {
            logger.info("orderItemInSetMenuList is empty");
            return orderItemList;
        }

        if (isEmpty(orderItemList)) {
            logger.info("may be some wrong, order item list is empty");
            return new ArrayList<>();
        }

        orderItemInSetMenuList.forEach(itemInSetMenu -> {
            Optional<OrderItem> itemOptional = orderItemList.stream().filter(item -> itemFilterFunction.apply(item, itemInSetMenu)).findAny();
            if (itemOptional.isPresent()) {
                OrderItem orderItem = itemOptional.get();
                orderItem.setReportValue(orderItem.getReportValue() + itemInSetMenu.getReportValue());
                orderItem.setCount(orderItem.getCount() + itemInSetMenu.getCount());
            } else {
                orderItemList.add(itemInSetMenu);
            }
        });

        return orderItemList;
    }

    /**
     * TOP 5的品类
     *
     * @param orderList
     * @return
     */
    public List<OrderItem> top5catalog(List<Order> orderList) {
        List<OrderItem> orderItemList = orderList.stream().flatMap(order -> getList(order.getOrderItemDetailList()).stream()).collect(Collectors.toList());
        orderItemList = orderItemList.stream().filter(item -> item.getCatalogId() != null).collect(Collectors.toList());

        Map<String, List<OrderItem>> itemIdMap = orderItemList.stream().collect(Collectors.groupingBy(orderItem -> {
            return orderItem.getCatalogName_en();
        }));

        orderItemList = itemIdMap.entrySet().stream().map(entity -> {
            List<OrderItem> orderItemListTmp = entity.getValue();
            OrderItem orderItem = new OrderItem();
            BeanUtils.copyProperties(orderItemListTmp.get(0), orderItem);

            double itemCost = orderItemListTmp.stream().mapToDouble(item -> getDouble(item.getItemPrice()) * getInt(item.getCount())).sum();
            //计算总和的金额以及数量
            orderItem.setReportValue(itemCost);
            return orderItem;
        }).collect(Collectors.toList());

        //计算套餐里面的菜的金额以及份数
        List<OrderItem> orderItemInSetMenuList = calOrderItemCashAndCountInSetMenu(orderList, item -> item.getCatalogName_en());
        //合并
        orderItemList = mergeOrderItem(orderItemList, orderItemInSetMenuList, (orderItem, orderItemInSetMenu) -> equals(orderItem.getCatalogName_en(), orderItemInSetMenu.getCatalogName_en()));

        //按照金额排序
        orderItemList = orderItemList.stream().sorted(Comparator.comparing(OrderItem::getReportValue).reversed()).collect(Collectors.toList());
        orderItemList.forEach(p -> p.setItemDetailList(null));
        orderItemList.forEach(p -> p.setDetailJson(null));
        orderItemList.forEach(p -> p.setSetMenuOneItemList(null));
        return CollectionUtil.getInstance().take(orderItemList, 5);
    }

    /**
     * 人数求和
     *
     * @param shopIdList
     * @param startTime
     * @param endTime
     * @return
     */
    public int sumPerson(List<Long> shopIdList, Long startTime, Long endTime) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        return getInt(orderDao.sumPerson(shopIdList, startTime, endTime));
    }

    /**
     * 平均客单价
     *
     * @param shopIdList
     * @param startTime
     * @param endTime
     * @return
     */
    public double avgPersonCost(List<Long> shopIdList, Long startTime, Long endTime) {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        return showMoneyDouble(orderDao.avgPersonCost(shopIdList, startTime, endTime));
    }

    /**
     * 每周每天的值的统计
     *
     * @param reportBo
     * @return
     */
    public List<Report> weekEveryDay(ReportBo reportBo) throws ResponseStatusException {

        VerifyUtil.verify(() -> isNotEmpty(reportBo.getShopIdList()));

        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        List<Tuple> tuples = orderDao.weekEveryDayAvg(reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getShopIdList());
        List<Report> reportList = new ArrayList<>();

        List<String> weekName = new ArrayList<>();
        //日
        weekName.add("Sunday");
        //一
        weekName.add("Monday");
        //二
        weekName.add("Tuesday");
        //三
        weekName.add("Wednesday");
        //四
        weekName.add("Thursday");
        //五
        weekName.add("Friday");
        //六
        weekName.add("Saturday");


        //每周的每天有默认值
        for (String string : weekName) {
            Report report = new Report();
            //星期的首写字母
            report.setX(String.valueOf(string.charAt(0)));
            //默认值
            if (isEmpty(tuples)) {
                report.setValue(0.0);
            }

            for (Tuple tuple : tuples) {
                if (equals(string, tuple.get(0))) {
                    report.setValue((Double) tuple.get(1));
                    break;
                }
                //部分没有设置默认值默认值
                report.setValue(0.0);
            }

            reportList.add(report);
        }

        return reportList;
    }

    /**
     * 一天每小时的统计
     *
     * @param reportBo
     * @return
     */
    public List<Report> hourOneDay(ReportBo reportBo) throws ResponseStatusException {
        VerifyUtil.verify(() -> isNotEmpty(reportBo.getShopIdList()));
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        List<Tuple> tuples = orderDao.hourOneDayAvg(reportBo.getStartTime(), reportBo.getEndTime(), reportBo.getShopIdList());
        List<Report> reportList = new ArrayList<>();

        //一天24小时
        for (int i = 0; i < 24; i++) {
            Report report = new Report();
            report.setX(String.valueOf(i));

            if (isEmpty(tuples)) {
                report.setValue(0.0);
            }
            for (Tuple tuple : tuples) {
                if (equals(String.valueOf(i), tuple.get(0))) {
                    report.setValue((Double) tuple.get(1));
                    break;
                }
                //给没有的一天赋值个默认值
                report.setValue(0.0);
            }
            reportList.add(report);
        }
        return reportList;
    }

    /**
     * 当日金额和数量销售额
     * @param shopIdList
     * @param startTime
     * @param endTime
     * @return
     * @throws Exception
     */
    public List<ShopReport> sumSalesAndCountList(List<Long> shopIdList, long startTime, long endTime) throws Exception {
        OrderDao orderDao = BeanUtil.getBean(OrderDao.class);
        //销售金额
        List<Tuple> sumSaleTuple = orderDao.sumSaleList(shopIdList, startTime, endTime, false, true, false);
        List<ShopReport> sumSaleReports = new ArrayList<>();
        for (Tuple tuple : sumSaleTuple) {
            ShopReport sumSaleReport = new ShopReport();
            NativeResultProcessUtils.convertTupleToBean(tuple, sumSaleReport);
            sumSaleReports.add(sumSaleReport);
        }


        List<ShopReport> sumCountReports = new ArrayList<>();
        //销售数量
        List<Tuple> sumCountTuple = orderDao.sumCountList(shopIdList, startTime, endTime, true);
        for (Tuple tuple : sumCountTuple) {
            ShopReport sumSaleReport = new ShopReport();
            NativeResultProcessUtils.convertTupleToBean(tuple, sumSaleReport);
            sumCountReports.add(sumSaleReport);
        }

        List<ShopReport> sumSalesAndCountReportList = new ArrayList<>();
        //多分店金额数量赋值
        for (Long shopId : shopIdList) {
            ShopReport shopReport = new ShopReport();
            Shop shop = ShopService.getInstance().findShopById(shopId);
            shopReport.setShopId(shopId);
            shopReport.setName(shop.getName());
            shopReport.setBusinessStatus(shop.getBusinessStatus());
            shopReport.setName_en(shop.getName_en());
            shopReport.setName_zh(shop.getName_zh());

            //分店相同就赋值金额
            for (ShopReport sumSaleReport : sumSaleReports) {
                if (equals(shopId, sumSaleReport.getShopId())) {
                    shopReport.setCash(sumSaleReport.getCash());
                }
            }


            //分店相同就赋值数量
            for (ShopReport sumCountReport : sumCountReports) {
                if (equals(shopId, sumCountReport.getShopId())) {
                    shopReport.setOrderNumber(sumCountReport.getOrderNumber());
                }

            }
            sumSalesAndCountReportList.add(shopReport);
        }
        return sumSalesAndCountReportList;
    }
}

